#include <gwbase/base/logging.h>
#include "dicom/gateway.h"
#include "dicom/sync_manager.h"
#include "gwbase/base/daemon.h"
#include "dicom/session.h"
#include <getopt.h>
#include <sys/resource.h>
#include "version.h"

using namespace dicom;

static struct option long_options[] = {{"version", no_argument, 0, 'v'},
                                       {"help", no_argument, 0, 'h'},
                                       {"conf", required_argument, 0, 'c'},
                                       {"debug", no_argument, 0, 'd'},
                                       {"daemon", no_argument, 0, 'x'},
                                       {0, 0, 0, 0}};

struct GatewayArgs {
  bool show_help;
  bool show_version;
  bool debug;
  bool daemon;
  std::string conf_file;

  GatewayArgs()
      : show_help(false),
        show_version(false),
        debug(false),
        daemon(false),
        conf_file("dicom.conf") {}

  bool TryParseOption(int argc, char** argv) {
    int c;
    while (true) {
      int option_index = 0;
      c = ::getopt_long(argc, argv, "vhc:dx", long_options, &option_index);
      if (c == -1) break;

      switch (c) {
        case 'v':
          this->show_version = true;
          break;
        case 'h':
          this->show_help = true;
          break;
        case 'c':
          this->conf_file = optarg;
          break;
        case 'd':
          this->debug = true;
          break;
        case 'x':
          this->daemon = true;
          break;
        default:
          return false;
      }
    }
    return true;
  }
};

static void ShowVersion() {
  printf("SurCloud Gateway Server (%s)\n", VERSION);
  printf("  Git Revision:   %s\n", GIT_SHA1);
  printf("  Cloud Backend:  %s\n", BACKEND);
}

static void ShowHelp() {
  printf("SurCloud Gateway Version: %s\n", VERSION);
  printf("Usage\n");
  printf("  dicom [-v] [-h] [-d] [-c <conf_file>]\n");
  printf("Options\n");
  printf("  -v, --version  show version\n");
  printf("  -h, --help     show this help\n");
  printf("  -d, --debug    enable debug log\n");
  printf("  -x, --daemon   run as daemon\n");
  printf(
      "  -c, --conf <conf_file>  use this config file, default is "
      "'dicom.conf'\n");
}

int Main(void* arg) {
  GatewayArgs* ga = static_cast<GatewayArgs*>(arg);
  if (ga == NULL) abort();

  if (ga->debug) {
    dicom::SetLogLevel(dicom::LogLevel::kLogTrace);
  }

  std::string conf_file = ga->conf_file;
  boost::shared_ptr<Conf> conf(new Conf());
  if (!conf->ParseFile(conf_file).ok()) {
    fprintf(stderr, "failed to parse config\n");
    return -1;
  }

  Gateway* gw = new Gateway();
  if (gw->LoadConfAndInit(conf_file, ga->daemon) == false) {
    LOG_ERROR << "failed to initiliaze gateway, abort...";
    return -1;
  }
  SetGateway(gw);
  gw->Start();

  return 0;
}

static void EnableCoreDump() {
  // core dumps may be disallowed by parent of this process; change that
  struct rlimit core_limits;
  core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
  setrlimit(RLIMIT_CORE, &core_limits);
}

int main(int argc, char** argv) {
  EnableCoreDump();

  GatewayArgs ga;
  if (ga.TryParseOption(argc, argv) == false) {
    return -1;
  }

  if (ga.show_help) {
    ShowHelp();
    return 0;
  }

  if (ga.show_version) {
    ShowVersion();
    return 0;
  }

  if (ga.daemon) {
    Daemon d(Main);
    d.Run(&ga);
    return 0;
  } else {
    return Main(&ga);
  }
}
